package com.zcxx.cotton.pick.service.impl;


import com.ruoyi.common.config.ApiConfig;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.zcxx.cotton.pick.domain.PickMapElement;
import com.zcxx.cotton.pick.mapper.PickMapElementMapper;
import com.zcxx.cotton.pick.service.IPickMapElementService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class PickMapElementServiceImpl implements IPickMapElementService {
    private static final Logger log = LoggerFactory.getLogger(PickMapElementServiceImpl.class);
    @Autowired
    private PickMapElementMapper pickMapElementMapper;

    @Autowired
    private ApiConfig apiConfig;

    @Override
    public List<PickMapElement> selectPickMapElementListByPid(Long pid) {
        return pickMapElementMapper.selectPickMapElementListByPid(pid);
    }

    @Override
    public List<PickMapElement> selectPickMapElementTreeList(String name) {
        long millis = System.currentTimeMillis();
        //SysUser sysUser = SecurityUtils.getLoginUser().getUser();
       /* if (sysUser == null){
            return Collections.emptyList();
        }*/
        Long deptId = apiConfig.getDeptId();

        try {
            List<PickMapElement> pickMapElements = pickMapElementMapper.selectPickMapElementList(deptId,name);
            System.out.println("查询数据结束已耗时"+(System.currentTimeMillis()-millis)+"ms");
            // 根据pid分组
            Map<Long, List<PickMapElement>> listMap = pickMapElements
                    .stream()
                    .collect(Collectors.groupingBy(
                            PickMapElement::getParentId,
                            Collectors.mapping(
                                    element -> element,
                                    Collectors.collectingAndThen(
                                            Collectors.toList(),
                                            elements -> {
                                                elements.sort(new Comparator<PickMapElement>() {
                                                    private final Pattern pattern = Pattern.compile("(\\d+)");

                                                    @Override
                                                    public int compare(PickMapElement o1, PickMapElement o2) {
                                                        String name1 = o1.getName();
                                                        String name2 = o2.getName();

                                                        Matcher matcher1 = pattern.matcher(name1);
                                                        Matcher matcher2 = pattern.matcher(name2);

                                                        while (matcher1.find() && matcher2.find()) {
                                                            int num1 = Integer.parseInt(matcher1.group(1));
                                                            int num2 = Integer.parseInt(matcher2.group(1));

                                                            if (num1 != num2) {
                                                                return Integer.compare(num1, num2);
                                                            }
                                                        }

                                                        // 如果数字部分相同，则按字符串比较
                                                        return name1.compareTo(name2);
                                                    }
                                                });
                                                return elements;
                                            }
                                    )
                            )
                    ));
            Long min = listMap.keySet().stream().min(Long::compareTo).orElse(null);
            System.out.println("排序结束已耗时"+(System.currentTimeMillis()-millis)+"ms");
            List<PickMapElement> rootNodes = new ArrayList<>();
            if (min != null) {
                int count=0;
                List<PickMapElement> rootElements = listMap.get(min);
                for (PickMapElement element : rootElements) {
                    count++;
                    buildTree(element, listMap,count);
                    rootNodes.add(element);
                }
            }
            System.out.println("构建树结束已耗时"+(System.currentTimeMillis()-millis)+"ms");
            return rootNodes;
        }catch (Exception e){
            e.printStackTrace();
            log.warn("该用户没有地块信息");
        }
        return Collections.emptyList();
    }


    @Override
    public int batchInsert(List<PickMapElement> list) {
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        if (sysUser == null){
            return 0;
        }
        Long deptId = apiConfig.getDeptId();
        //pickMapElementMapper.createTable(deptId);
        return pickMapElementMapper.batchInsert(list, deptId);
    }

    @Override
    public int batchUpdate(List<PickMapElement> list,String tableName) {
        return pickMapElementMapper.batchUpdate(list, tableName);
    }


    @Override
    public List<PickMapElement> selectAll(String tableName,String category) {
        return pickMapElementMapper.selectAll(tableName,category);
    }


    private void buildTree(PickMapElement node, Map<Long, List<PickMapElement>> groupedByPid,int count) {
        List<PickMapElement> children = groupedByPid.getOrDefault(node.getId(), Collections.emptyList());
        children.stream().forEach(item -> item.setColor(count));
        node.setChildren(children);
        node.setChild(children.size());
        node.setColor(count);
        // 构建经纬度属性
        if (node.getType()!=30){
            String detail = node.getDetail();
            String[] split = detail.split(",");
            String[] latlng = new String[split.length/2];

            if (split.length>2){
                for (int i = 0; i < split.length; i++) {
                    if (i%2==0 && i+1 < split.length){
                        latlng[i/2] = split[i+1] + "," + split[i];
                    }
                }

                List<String> stringList = Arrays.asList(latlng);
                // 计算面积周长等信息
                double area = calculateArea(stringList);
                double areaMu = area / SQUARE_METER_TO_MU;
                double perimeter = calculatePerimeter(stringList);
                String areaStr = "顶点个数:"+ stringList.size() + "<br>"
                        + " 参考周长:" + String.format("%.2f",perimeter) + " 米<br>"
                        + " 参考面积:" + String.format("%.2f",area)  + " 平方米<br>"
                        + String.format("%.2f",areaMu) + " 亩<br>";

                node.setAreaDetail(areaStr);


            }else if (split.length==2){
                latlng[0] = split[1] + "," + split[0];
            }
            node.setLatlng(latlng);


        }
        int totalDescendants = 0;  // 用于累计所有后代节点数量
        for (PickMapElement child : children) {
            buildTree(child, groupedByPid,count);
            totalDescendants += child.getChildSum() + 1; // 加上当前子节点
        }
        node.setChildSum(totalDescendants); // 设置所有后代节点数量
    }
    private static final double EARTH_RADIUS =  6371000; // 地球半径，单位为米
    private static final double SQUARE_METER_TO_MU = 666.6666667;// 1亩 = 666.67平方米

    /**
     * 计算面积
     * @param coordinates
     * @return
     */
    private static double calculateArea(List<String> coordinates) {
        if (coordinates.size() < 3) {
            return 0; // 至少需要三个点才能形成多边形
        }

        double total = 0;
        for (int i = 0; i < coordinates.size(); i++) {

            String[] point1 = coordinates.get(i).split(",");
            String[] point2 = coordinates.get((i + 1) % coordinates.size()).split(",");
            double lat1 = Math.toRadians(Double.parseDouble(point1[1]));
            double lon1 = Math.toRadians(Double.parseDouble(point1[0]));
            double lat2 = Math.toRadians(Double.parseDouble(point2[1]));
            double lon2 = Math.toRadians(Double.parseDouble(point2[0]));

            total += (lon2 - lon1) * (Math.sin(lat1) + Math.sin(lat2));
        }
        total = total * EARTH_RADIUS * EARTH_RADIUS / 2;

        return Math.abs(total);
    }
    /**
     * 计算周长
     * @param coordinates
     * @return
     */
    private static double calculatePerimeter(List<String> coordinates) {
        if (coordinates.size() < 2) {
            return 0; // 至少需要两个点才能计算距离
        }

        double totalDistance = 0;
        for (int i = 0; i < coordinates.size(); i++) {

            String[] point1 = coordinates.get(i).split(",");
            String[] point2 = coordinates.get((i + 1) % coordinates.size()).split(",");
            double lat1 = Math.toRadians(Double.parseDouble(point1[1]));
            double lon1 = Math.toRadians(Double.parseDouble(point1[0]));
            double lat2 = Math.toRadians(Double.parseDouble(point2[1]));
            double lon2 = Math.toRadians(Double.parseDouble(point2[0]));

            double dLat = lat2 - lat1;
            double dLon = lon2 - lon1;

            double a = Math.pow(Math.sin(dLat / 2), 2) +
                    Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dLon / 2), 2);
            double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

            totalDistance += EARTH_RADIUS * c;
        }

        return totalDistance;
    }


    @Override
    public Double getArea(String detail) {
        String[] split = detail.split(",");
        String[] latlng = new String[split.length/2];

        if (split.length>2){

            for (int i = 0; i < split.length; i++) {
                if (i%2==0 && i+1 < split.length){
                    latlng[i/2] = split[i+1] + "," + split[i];
                }
            }

            List<String> stringList = Arrays.asList(latlng);
            // 计算面积周长等信息
            double area = calculateArea(stringList);
            return area / SQUARE_METER_TO_MU;
        }
        return 0.0;
     }

    @Override
    public BigDecimal selectTotalArea(String category) {
        return pickMapElementMapper.selectTotalArea(category);
    }


}
